﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using BaseLibrary;

namespace CodeToAddresConverter
{
    class Program
    {
        static Dictionary<string, Label> labels = new Dictionary<string, Label>();
        static Dictionary<string, Label> vars = new Dictionary<string, Label>();
        static int _mem_ptr = 0;

        //На входе файл с программой для мэна, содержащей имена функций как коды
        //На выходе пишет в консоль такую же программу, но с адресами
        static void Main(string[] args)
        {
            if (args.Length > 0)
                using (var r = new StreamReader(args[0]))
                    Convert(r);
            //Convert(new StreamReader("input.txt"));
        }

        static Label RegisterVar(string s)
        {
            bool isVariable = !String.IsNullOrEmpty(s) && s.StartsWith("$");
            if (isVariable)
            {
                if (!vars.ContainsKey(s))
                    vars.Add(s, new Label(s) { Number = _mem_ptr++ });
                return vars[s];
            }
            return null;
        }

        static Label RegisterLabel(string s)
        {
            bool isLabel = !String.IsNullOrEmpty(s) && s.StartsWith("_");
            if (isLabel)
            {
                if (!labels.ContainsKey(s))
                    labels.Add(s, new Label(s));
                return labels[s];
            }
            return null;
        }

        private static void Convert(StreamReader reader)
        {
            try
            {
                int n = 0;
                var commands = new List<Command>();
                string curfun = "";
                string s;
                while ((s = reader.ReadLine()) != null)
                {
                    var com = new Command(s);
                    if (!com.Function.IsEmpty())
                    {
                        if (!labels.ContainsKey(com.Function))
                            labels.Add(com.Function, new Label(com.Function));
                        labels[com.Function].Number = n;
                        curfun = com.Function;
                    }
                    else
                    {
                        if (!curfun.IsEmpty())
                        {
                            com.Function = curfun;
                            curfun = "";
                        }
                        var code = com.Code.ToUpper();
                        var param1 = com.Param1.ToUpper();

                        // Variables
                        if ((code == "INC") || (code == "DEC"))
                        {
                            com.Var1 = RegisterVar(com.Param1);
                        }

                        if ((code == "MOV") || (code == "ADD") || (code == "SUB") || 
                            (code == "MUL") || (code == "DIV") || (code == "AND") || (code == "OR") ||
                            (code == "XOR") || (code == "OR"))
                        {
                            com.Var1 = RegisterVar(com.Param1);
                            com.Var2 = RegisterVar(com.Param2);
                        }

                        if ((code == "JLT") || (code == "JEQ") || (code == "JGT"))
                        {
                            com.Label1 = RegisterLabel(com.Param1);
                            com.Var2 = RegisterVar(com.Param2);
                            com.Var3 = RegisterVar(com.Param3);
                        }

                        // Labels
                        if (code == "MOV")
                        {
                            com.Label2 = RegisterLabel(com.Param2);
                        }
                        if (!com.Code.IsEmpty())
                        {
                            com.Number = n;
                            n++;
                        }
                        if (commands.Count != 0) 
                            commands[commands.Count - 1].NextCommand = com;
                        commands.Add(com);
                    }
                }
                int i = commands.Count - 1;
                while (i >= 0 && commands[i].Code.IsEmpty())
                    i--;
                commands.RemoveRange(i + 1, commands.Count - i - 1);

                foreach (var com in commands)
                    Console.WriteLine(com.Write());
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Error: {0}", ex.Message);
            }
        }
    }
}
